package com.daji.concurrency.multithread_synchronized;


/*
    这个小小的例子可以有三种方法同步(也就是synchronized)临界资源count
    我们期望的最终结果是：最终计数加了1w次，减了1w次，最终得到的结果是0

    我们现在有三种方法达到该目的。第一种方法是同B02的方法。
    第二种方法是给当前对象加一个this锁
    第三种方法是给方法加锁
    第二种方法和第三种方法完全等价。

    三种方法都可以取得该效果，其中第二，三种方法是我们要介绍的主题：同步方法.

    为什么我们不建议使用方法一呢？原因如下：
        我们注意到，synchronized锁住的对象是this，即当前实例，
        这又使得创建多个Counter实例的时候，它们之间互不影响，可以并发执行。
        大吉注：多个实例之间 是并发的，单个实例操作临界资源，又是同步的。这是方法一很难做到的。
               如果是类锁，则是另一种情况。详见下文类锁。
               如果是类锁，则是另一种情况。详见下文类锁。

    给this对象加锁是个既能保证单个实例同步，多个实例之间并发的好主意。
*/
public class B04_SynchronizedMethod {
    public static void main(String[] args) throws InterruptedException {
        Counter3 c1 = new Counter3();
        Thread t1 = new Thread(() -> {

            //synchronized ("daji"){    //方法1：同B02
                c1.add();
            //}
        });
        Thread t2 = new Thread(() -> {
            //synchronized ("daji"){    //方法1：同B02
                c1.dec();
            //}
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("最终计数为："+c1.get());
    }
}

class Counter3 {
    private int count = 0;

    public synchronized void add() {    //方法三：同步方法
        //synchronized(this) {  //方法二：给当前对象加this锁，它与方法三等价
            for (int i = 0; i < 10000; i++) {
                count += 1;
            }
        //}
    }

    public synchronized void dec() {    //方法三：同步方法
        //synchronized(this) {  //方法二：给当前对象加this锁，它与方法三等价
            for (int i = 0; i < 10000; i++) {
                count -= 1;
            }
        //}
    }

    public int get() {
        return count;
    }
    /*
        思考：如果对一个静态方法添加synchronized修饰符，它锁住的是哪个对象？

        对于static方法，是没有this实例的，因为static方法是针对类而不是实例。但是我们注意到任何一个类都有一个由JVM自动创建的Class实例，
        因此，对static方法添加synchronized，锁住的是该类的Class实例。上述synchronized static方法实际上相当于：

        public class Counter {
        public static void test(int n) {
            synchronized(Counter.class) {   //类锁
                ...
            }
        }
    }
        进一步思考，类锁和对象锁又有什么区别呢？
        进一步思考，类锁和对象锁又有什么区别呢？
        进一步思考，类锁和对象锁又有什么区别呢？
        上文说的对象锁可以保证：多个实例之间 是并发的，单个实例操作临界资源，又是同步的。
        如果换成了类锁：synchronized(Counter.class) 那就成了该类的多个实例之间也是同步了，这样是完全串行化的
        类锁和对象锁的区别很有用，尤其是设计模式的单例模式有应用！

    参考资料：廖雪峰的官方网站 https://www.liaoxuefeng.com/wiki/1252599548343744/1306580867874849
    */
}